/*
* This is a common dao with basic CRUD operations and is not limited to any
* persistent layer implementation
*
* Copyright (C) 2008 Imran M Yousuf (imyousuf@smartitengineering.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.smartitengineering.dao.impl.hibernate;
import com.smartitengineering.dao.common.queryparam.BasicCompoundQueryParameter;
import com.smartitengineering.dao.common.queryparam.BiOperandQueryParameter;
import com.smartitengineering.dao.common.queryparam.CompositionQueryParameter;
import com.smartitengineering.dao.common.queryparam.OperatorType;
import com.smartitengineering.dao.common.queryparam.QueryParameter;
import com.smartitengineering.dao.common.queryparam.QueryParameterCastHelper;
import com.smartitengineering.dao.common.queryparam.QueryParameterWithOperator;
import com.smartitengineering.dao.common.queryparam.QueryParameterWithPropertyName;
import com.smartitengineering.dao.common.queryparam.QueryParameterWithValue;
import com.smartitengineering.dao.common.queryparam.SimpleNameValueQueryParameter;
import com.smartitengineering.dao.common.queryparam.ValueOnlyQueryParameter;
import com.smartitengineering.domain.PersistentDTO;
import java.io.Serializable;
import java.util.Collection;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import org.hibernate.Criteria;
import org.hibernate.FetchMode;
import org.hibernate.Session;
import org.hibernate.criterion.AggregateProjection;
import org.hibernate.criterion.Conjunction;
import org.hibernate.criterion.CountProjection;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Junction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.PropertyProjection;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public abstract class AbstractDAO<Template extends PersistentDTO>
extends HibernateDaoSupport
implements Serializable {
private Map<Criteria, ProjectionList> projections =
new WeakHashMap<Criteria, ProjectionList>();
protected void createEntity(Template... entities) {
if (entities == null) {
throw new IllegalArgumentException();
}
Session session;
boolean customSession = false;
try {
session = getSessionFactory().getCurrentSession();
}
catch (Exception ex) {
session = getSessionFactory().openSession();
customSession = true;
}
try {
for (Template entity : entities) {
session.save(entity);
}
}
finally {
if (session != null) {
session.flush();
if (customSession && session.isOpen()) {
session.close();
}
}
}
}
protected void updateEntity(Template... entities) {
if (entities == null) {
throw new IllegalArgumentException();
}
Session session;
boolean customSession = false;
try {
session = getSessionFactory().getCurrentSession();
}
catch (Exception ex) {
session = getSessionFactory().openSession();
customSession = true;
}
try {
for (Template entity : entities) {
session.update(entity);
}
}
finally {
if (session != null) {
session.flush();
if (customSession && session.isOpen()) {
session.close();
}
}
}
}
protected void deleteEntity(Template... entities) {
if (entities == null) {
throw new IllegalArgumentException();
}
Session session;
boolean customSession = false;
try {
session = getSessionFactory().getCurrentSession();
}
catch (Exception ex) {
session = getSessionFactory().openSession();
customSession = true;
}
try {
for (Template entity : entities) {
session.delete(entity);
}
}
finally {
if (session != null) {
session.flush();
if (customSession && session.isOpen()) {
session.close();
}
}
}
}
protected Template readSingle(Class entityClass,
Hashtable<String, QueryParameter> parameter) {
return readSingle(entityClass, parameter.values().toArray(
new QueryParameter[0]));
}
protected Object readOther(Class entityClass,
Hashtable<String, QueryParameter> parameter) {
return readOther(entityClass, parameter.values().toArray(
new QueryParameter[0]));
}
protected List<? extends Object> readOtherList(Class entityClass,
Hashtable<String, QueryParameter> parameter) {
return readOtherList(entityClass, parameter.values().toArray(
new QueryParameter[0]));
}
protected List<Template> readList(Class entityClass,
Hashtable<String, QueryParameter> parameter) {
return readList(entityClass, parameter.values().toArray(
new QueryParameter[0]));
}
protected Template readSingle(Class entityClass,
List<QueryParameter> parameter) {
return readSingle(entityClass, parameter.toArray(new QueryParameter[0]));
}
protected <OtherTemplate extends Object> OtherTemplate readOther(
Class entityClass,
List<QueryParameter> parameter) {
return this.<OtherTemplate>readOther(entityClass, parameter.toArray(new QueryParameter[0]));
}
protected <OtherTemplate extends Object> List<OtherTemplate> readOtherList(
Class entityClass,
List<QueryParameter> parameter) {
return readOtherList(entityClass, parameter.toArray(
new QueryParameter[0]));
}
protected List<Template> readList(Class entityClass,
List<QueryParameter> parameter) {
return readList(entityClass, parameter.toArray(new QueryParameter[0]));
}
protected Template readSingle(Class entityClass,
QueryParameter... parameter) {
Session session;
boolean customSession = false;
try {
session = getSessionFactory().getCurrentSession();
}
catch (Exception ex) {
session = getSessionFactory().openSession();
customSession = true;
}
try {
Criteria criteria = simpleSearchCriteria(session, entityClass,
parameter);
return (Template) criteria.uniqueResult();
}
catch (Exception e) {
throw new IllegalArgumentException(e);
}
finally {
if (session != null) {
if (customSession && session.isOpen()) {
session.close();
}
}
}
}
protected <OtherTemplate extends Object> OtherTemplate readOther(
Class entityClass,
QueryParameter... parameter) {
Session session;
boolean customSession = false;
try {
session = getSessionFactory().getCurrentSession();
}
catch (Exception ex) {
session = getSessionFactory().openSession();
customSession = true;
}
try {
Criteria criteria = simpleSearchCriteria(session, entityClass,
parameter);
return (OtherTemplate) criteria.uniqueResult();
}
catch (Exception e) {
throw new IllegalArgumentException(e);
}
finally {
if (session != null) {
if (customSession && session.isOpen()) {
session.close();
}
}
}
}
protected <OtherTemplate extends Object> List<OtherTemplate> readOtherList(
Class entityClass,
QueryParameter... parameter) {
Session session;
boolean customSession = false;
try {
session = getSessionFactory().getCurrentSession();
}
catch (Exception ex) {
session = getSessionFactory().openSession();
customSession = true;
}
try {
Criteria criteria = simpleSearchCriteria(session, entityClass,
parameter);
return criteria.list();
}
catch (Exception e) {
throw new IllegalArgumentException(e);
}
finally {
if (session != null) {
if (customSession && session.isOpen()) {
session.close();
}
}
}
}
protected List<Template> readList(Class entityClass,
QueryParameter... parameter) {
Session session;
boolean customSession = false;
try {
session = getSessionFactory().getCurrentSession();
}
catch (Exception ex) {
session = getSessionFactory().openSession();
customSession = true;
}
try {
Criteria criteria = simpleSearchCriteria(session, entityClass,
parameter);
return criteria.list();
}
catch (Exception e) {
throw new IllegalArgumentException(e);
}
finally {
if (session != null) {
if (customSession && session.isOpen()) {
session.close();
}
}
}
}
protected Criteria simpleSearchCriteria(Session session,
Class queryClass,
QueryParameter... parameter) {
Criteria criteria = session.createCriteria(queryClass);
for (QueryParameter param : parameter) {
if (!param.isInitialized()) {
continue;
}
String propertyName = getPropertyName(param);
processCriteria(criteria, propertyName, param);
}
return criteria;
}
@SuppressWarnings("unchecked")
private void processCriteria(Criteria criteria,
String element,
QueryParameter parameter) {
switch (parameter.getParameterType()) {
case PARAMETER_TYPE_PROPERTY: {
criteria.add(getCriterion(element, parameter));
return;
}
case PARAMETER_TYPE_ORDER_BY: {
final Order order;
SimpleNameValueQueryParameter<com.smartitengineering.dao.common.queryparam.Order> queryParameter =
QueryParameterCastHelper.SIMPLE_PARAM_HELPER.cast(parameter);
com.smartitengineering.dao.common.queryparam.Order requestedOrder =
queryParameter.getValue();
switch (requestedOrder) {
case ASC: {
order = Order.asc(element);
break;
}
case DESC: {
order = Order.desc(element);
break;
}
default: {
order = null;
break;
}
}
if (order != null) {
criteria.addOrder(order);
}
return;
}
case PARAMETER_TYPE_MAX_RESULT: {
ValueOnlyQueryParameter<Integer> queryParameter =
QueryParameterCastHelper.VALUE_PARAM_HELPER.cast(parameter);
criteria.setMaxResults(queryParameter.getValue());
return;
}
case PARAMETER_TYPE_FIRST_RESULT: {
ValueOnlyQueryParameter<Integer> queryParameter =
QueryParameterCastHelper.VALUE_PARAM_HELPER.cast(parameter);
criteria.setFirstResult(queryParameter.getValue());
return;
}
case PARAMETER_TYPE_DISJUNCTION: {
processDisjunction(criteria, parameter);
return;
}
case PARAMETER_TYPE_CONJUNCTION: {
processConjunction(criteria, parameter);
return;
}
case PARAMETER_TYPE_NESTED_PROPERTY: {
processNestedParameter(criteria, element, parameter);
return;
}
case PARAMETER_TYPE_COUNT: {
final Projection countProjection = Projections.count(element);
setProjection(criteria, countProjection);
return;
}
case PARAMETER_TYPE_ROW_COUNT: {
final Projection rowCount = Projections.rowCount();
setProjection(criteria, rowCount);
return;
}
case PARAMETER_TYPE_SUM: {
final AggregateProjection sum = Projections.sum(element);
setProjection(criteria, sum);
return;
}
case PARAMETER_TYPE_MAX: {
final AggregateProjection max = Projections.max(element);
setProjection(criteria, max);
return;
}
case PARAMETER_TYPE_MIN: {
final AggregateProjection min = Projections.min(element);
setProjection(criteria, min);
return;
}
case PARAMETER_TYPE_AVG: {
final AggregateProjection avg = Projections.avg(element);
setProjection(criteria, avg);
return;
}
case PARAMETER_TYPE_GROUP_BY: {
final PropertyProjection groupProperty =
Projections.groupProperty(element);
setProjection(criteria, groupProperty);
return;
}
case PARAMETER_TYPE_COUNT_DISTINCT: {
final CountProjection countDistinct =
Projections.countDistinct(element);
setProjection(criteria, countDistinct);
return;
}
case PARAMETER_TYPE_DISTINCT_PROP: {
final Projection distinct =
Projections.distinct(Projections.property(element));
setProjection(criteria, distinct);
return;
}
case PARAMETER_TYPE_UNIT_PROP: {
final PropertyProjection property =
Projections.property(element);
setProjection(criteria, property);
return;
}
}
}
@SuppressWarnings("unchecked")
private void processNestedParameter(Criteria criteria,
String element,
QueryParameter parameter) {
FetchMode mode;
CompositionQueryParameter queryParameter =
QueryParameterCastHelper.COMPOSITION_PARAM_FOR_NESTED_TYPE.cast(
parameter);
switch (queryParameter.getFetchMode()) {
case EAGER:
mode = FetchMode.EAGER;
break;
case SELECT:
mode = FetchMode.SELECT;
break;
case JOIN:
mode = FetchMode.JOIN;
break;
case LAZY:
mode = FetchMode.LAZY;
break;
default:
case DEFAULT:
mode = FetchMode.DEFAULT;
break;
}
criteria.setFetchMode(element, ((mode == null) ? FetchMode.JOIN : mode));
Collection<QueryParameter> nestedParameters = queryParameter.
getNestedParameters();
if (nestedParameters == null || nestedParameters.size() <= 0) {
return;
}
Criteria nestedCriteria = criteria.createCriteria(element);
for (QueryParameter nestedQueryParameter : nestedParameters) {
if (!nestedQueryParameter.isInitialized()) {
continue;
}
processCriteria(nestedCriteria,
getPropertyName(nestedQueryParameter), nestedQueryParameter);
}
}
@SuppressWarnings("unchecked")
private void processCriterion(Junction criterion,
String element,
QueryParameter parameter) {
switch (parameter.getParameterType()) {
case PARAMETER_TYPE_PROPERTY: {
criterion.add(getCriterion(element, parameter));
return;
}
case PARAMETER_TYPE_CONJUNCTION: {
processConjunction(criterion, parameter);
break;
}
case PARAMETER_TYPE_DISJUNCTION: {
processDisjunction(criterion, parameter);
break;
}
}
}
@SuppressWarnings("unchecked")
private void processDisjunction(Criteria criteria,
QueryParameter parameter) {
Disjunction disjunction = Expression.disjunction();
workOnNestedParams(parameter, disjunction);
criteria.add(disjunction);
}
@SuppressWarnings("unchecked")
private void processConjunction(Criteria criteria,
QueryParameter parameter) {
Conjunction conjunction = Expression.conjunction();
workOnNestedParams(parameter, conjunction);
criteria.add(conjunction);
}
@SuppressWarnings("unchecked")
private void processDisjunction(Junction junction,
QueryParameter parameter) {
Disjunction disjunction = Expression.disjunction();
workOnNestedParams(parameter, disjunction);
junction.add(disjunction);
}
@SuppressWarnings("unchecked")
private void processConjunction(Junction junction,
QueryParameter parameter) {
Conjunction conjunction = Expression.conjunction();
workOnNestedParams(parameter, conjunction);
junction.add(conjunction);
}
private Criterion getCriterion(String element,
QueryParameter queryParamemter) {
OperatorType operator = getOperator(queryParamemter);
Object parameter = getValue(queryParamemter);
switch (operator) {
case OPERATOR_EQUAL: {
return Expression.eq(element, parameter);
}
case OPERATOR_LESSER: {
return Expression.lt(element, parameter);
}
case OPERATOR_LESSER_EQUAL: {
return Expression.le(element, parameter);
}
case OPERATOR_GREATER: {
return Expression.gt(element, parameter);
}
case OPERATOR_GREATER_EQUAL: {
return Expression.ge(element, parameter);
}
case OPERATOR_NOT_EQUAL: {
return Expression.ne(element, parameter);
}
case OPERATOR_IS_NULL: {
return Expression.isNull(element);
}
case OPERATOR_IS_NOT_NULL: {
return Expression.isNotNull(element);
}
case OPERATOR_IS_EMPTY: {
return Expression.isEmpty(element);
}
case OPERATOR_IS_NOT_EMPTY: {
return Expression.isNotEmpty(element);
}
case OPERATOR_STRING_LIKE: {
MatchMode hibernateMatchMode;
com.smartitengineering.dao.common.queryparam.MatchMode matchMode =
getMatchMode(queryParamemter);
if (matchMode == null) {
matchMode =
com.smartitengineering.dao.common.queryparam.MatchMode.EXACT;
}
switch (matchMode) {
case END:
hibernateMatchMode = MatchMode.END;
break;
case EXACT:
hibernateMatchMode = MatchMode.EXACT;
break;
case START:
hibernateMatchMode = MatchMode.START;
break;
default:
case ANYWHERE:
hibernateMatchMode = MatchMode.ANYWHERE;
break;
}
return Expression.like(element, parameter.toString(),
hibernateMatchMode);
}
case OPERATOR_BETWEEN: {
parameter = getFirstParameter(queryParamemter);
Object parameter2 = getSecondParameter(queryParamemter);
return Expression.between(element, parameter, parameter2);
}
case OPERATOR_IS_IN: {
Collection inCollectin =
QueryParameterCastHelper.MULTI_OPERAND_PARAM_HELPER.cast(
queryParamemter).getValues();
return Restrictions.in(element, inCollectin);
}
case OPERATOR_IS_NOT_IN: {
Collection inCollectin =
QueryParameterCastHelper.MULTI_OPERAND_PARAM_HELPER.cast(
queryParamemter).getValues();
return Restrictions.not(Restrictions.in(element, inCollectin));
}
}
return null;
}
private String getPropertyName(
QueryParameter param) {
final String propertyName;
if (param instanceof QueryParameterWithPropertyName) {
propertyName =
((QueryParameterWithPropertyName) param).getPropertyName();
}
else {
propertyName = "";
}
return propertyName;
}
private void setProjection(Criteria criteria,
final Projection projection) {
ProjectionList currentProjections = projections.get(
criteria);
if (currentProjections == null) {
currentProjections = Projections.projectionList();
projections.put(criteria, currentProjections);
criteria.setProjection(currentProjections);
}
currentProjections.add(projection);
}
private void workOnNestedParams(QueryParameter parameter,
Junction criterion) {
BasicCompoundQueryParameter queryParameter =
QueryParameterCastHelper.BASIC_COMPOUND_PARAM_HELPER.cast(parameter);
Collection<QueryParameter> nestedParameters =
queryParameter.getNestedParameters();
for (QueryParameter nestedParam : nestedParameters) {
if (!nestedParam.isInitialized()) {
continue;
}
processCriterion(criterion, getPropertyName(nestedParam),
nestedParam);
}
}
private OperatorType getOperator(QueryParameter queryParamemter) {
if (QueryParameterCastHelper.BASIC_COMPOUND_PARAM_HELPER.isWithOperator(
queryParamemter)) {
QueryParameterWithOperator parameterWithOperator =
QueryParameterCastHelper.BI_OPERAND_PARAM_HELPER.
castToOperatorParam(
queryParamemter);
return parameterWithOperator.getOperatorType();
}
else {
return null;
}
}
private Object getValue(QueryParameter queryParamemter) {
Object value;
if (queryParamemter instanceof QueryParameterWithValue) {
value = ((QueryParameterWithValue) queryParamemter).getValue();
}
else {
value = null;
}
if (value == null) {
value = "";
}
return value;
}
private Object getSecondParameter(QueryParameter queryParamemter) {
if (queryParamemter instanceof BiOperandQueryParameter) {
return QueryParameterCastHelper.BI_OPERAND_PARAM_HELPER.cast(
queryParamemter).getSecondValue();
}
else {
return "";
}
}
private Object getFirstParameter(QueryParameter queryParamemter) {
if (queryParamemter instanceof BiOperandQueryParameter) {
return QueryParameterCastHelper.BI_OPERAND_PARAM_HELPER.cast(
queryParamemter).getFirstValue();
}
else {
return "";
}
}
private com.smartitengineering.dao.common.queryparam.MatchMode getMatchMode(
QueryParameter queryParamemter) {
return QueryParameterCastHelper.STRING_PARAM_HELPER.cast(queryParamemter).
getMatchMode();
}
}